//	Project:	HexTower
//	File:		DirectInput_Manager.cpp
//	Author:		Mustafa Aldoori
//	Purpose:	Direct Input Manager implementation.

#include "DirectInput_Manager.h"
#include <tchar.h>

//	MessageBox for Errors that occur within DirectInput.
#ifndef DIERRBOX
	#define DIERRBOX(hWnd, errorText)	{ MessageBox(hWnd, errorText, _T("DirectInput Error"), MB_OK | MB_ICONEXCLAMATION); }
#endif

DirectInput_Manager DirectInput_Manager::m_Instance;

DirectInput_Manager* DirectInput_Manager::GetInstance( void )
{
	return &m_Instance;
}

DirectInput_Manager::DirectInput_Manager( void )
{
	m_lpDIObject	= nullptr;
	m_pKeyboard		= nullptr;
	m_pMouse		= nullptr;
}

DirectInput_Manager::~DirectInput_Manager( void )
{
	ShutdownDirectInput();
}

//	Purpose	:	To initialize the DirectInput Object and requested devices.
bool DirectInput_Manager::InitDirectInput( HWND hWnd, HINSTANCE hInstance, unsigned int unInitDevices, unsigned int unExclusiveDevices)
{
	//	Create the DirectInput Object
	if (FAILED( DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_lpDIObject, NULL) ))
		return false;

	//	Initialize the keyboard if the keyboard flag is on
	if ( unInitDevices & DI_KEYBOARD )
	{
		//	Initialize the keyboard
		if (!InitKeyboard(hWnd, (unExclusiveDevices & DI_KEYBOARD) ? true : false ))
			return false;
	}

	//	Initialize the mouse if the mouse flag is on
	if ( unInitDevices & DI_MOUSE )
	{
		//	Initialize the mouse
		if (!InitMouse(hWnd, (unExclusiveDevices & DI_MOUSE) ? true : false ))
			return false;
	}

	//	Initialize joysticks if the joystick flag is on
	if ( unInitDevices & DI_JOYSTICKS )
	{
		//	Initialize joysticks
		if (!InitJoysticks(hWnd, (unExclusiveDevices & DI_JOYSTICKS) ? true : false ))
			return false;
	}

	//	Return success.
	return true;
}

//	Purpose:	Shuts down DirectInput and any initialized devices.
void DirectInput_Manager::ShutdownDirectInput( void )
{
	UnacquireAll();

	if (m_pKeyboard)
	{
		Safe_Delete(m_pKeyboard);
	}

	if (m_pMouse)
	{
		Safe_Delete(m_pMouse);
	}

	if (m_vpJoysticks.size() > 0)
	{
		for (unsigned int i=0; i < m_vpJoysticks.size(); i++)
		{
			Safe_Delete(m_vpJoysticks[i]);
		}

		m_vpJoysticks.clear();
	}
}

//	Purpose	:	Gets the state of all the initialized devices.
void DirectInput_Manager::ReadDevices(void)
{
	if (m_pKeyboard)
	{
		m_pKeyboard->ReadDevice();
		m_pKeyboard->ReadBufferedDevice();
	}

	if (m_pMouse)
	{
		m_pMouse->ReadDevice();
		m_pMouse->ReadBufferedDevice();
	}
	
	if (m_vpJoysticks.size() > 0)
	{
		for (unsigned int i=0; i < m_vpJoysticks.size(); i++)
		{
			if (m_vpJoysticks[i])
			{
				m_vpJoysticks[i]->ReadDevice();
				m_vpJoysticks[i]->ReadBufferedDevice();
			}
		}
	}
}

//	Purpose	:	Clears out the input for all the initialized devices.
void DirectInput_Manager::ClearInput(void)
{
	if (m_pKeyboard)
	{
		m_pKeyboard->ClearKeys();
	}

	if (m_pMouse)
	{
		m_pMouse->ClearMouseButtons();
	}

	if (m_vpJoysticks.size() > 0)
	{
		for (unsigned int i=0; i < m_vpJoysticks.size(); i++)
		{
			if (m_vpJoysticks[i])
			{
				m_vpJoysticks[i]->ClearJoystickButtons();
			}
		}
	}
}

//	Purpose	:	Acquires all the initialized direct input devices (i.e. keyboard, mouse, and joysticks).
//				Ideally called when the application gains focus.
void DirectInput_Manager::AcquireAll(void)
{
	if (m_pKeyboard)
		m_pKeyboard->Acquire();

	if (m_pMouse)
		m_pMouse->Acquire();
	
	if (m_vpJoysticks.size() > 0)
	{
		for (unsigned int i=0; i < m_vpJoysticks.size(); i++)
		{
			if (m_vpJoysticks[i]) 
				m_vpJoysticks[i]->Acquire();
		}
	}
}

//	Purpose	:	Unacquires all the initialized direct input devices (i.e. keyboard, mouse, and joysticks).
//				Ideally called when the application loses focus.
void DirectInput_Manager::UnacquireAll(void)
{
	if (m_pKeyboard)
		m_pKeyboard->Unacquire();

	if (m_pMouse)
		m_pMouse->Unacquire();

	if (m_vpJoysticks.size() > 0)
	{
		for (unsigned int i=0; i < m_vpJoysticks.size(); i++)
		{
			if (m_vpJoysticks[i]) 
				m_vpJoysticks[i]->Unacquire();
		}
	}
}

///////////////////////////////////////////////////////////////////
//						KEYBOARD								 //
///////////////////////////////////////////////////////////////////

//	Purpose	:	Initialize the Keyboard for DirectInput.
bool DirectInput_Manager::InitKeyboard(HWND hWnd, bool bIsExclusive)
{
	//	Make sure we aren't trying to do this a second time.
	if (m_pKeyboard)
	{
		DIERRBOX(hWnd, _T("Keyboard has already been initialized"))
		return false;
	}

	m_pKeyboard = new DIKeyboard(m_lpDIObject, hWnd, bIsExclusive);
	
	if (m_pKeyboard == NULL)
		return false;

	return true;
}

//	Purpose	:	Gets the current (immediate) state of a Key.
bool DirectInput_Manager::KeyDown(unsigned char ucDIKey)			{ return (m_pKeyboard && m_pKeyboard->KeyDown(ucDIKey)); }

//	Purpose	:	To tell if a key was just pressed (without using DirectInput's Buffered Input).
bool DirectInput_Manager::KeyPressed(unsigned char ucDIKey)			{ return (m_pKeyboard && m_pKeyboard->KeyPressed(ucDIKey)); }

//	Purpose	:	To tell if a key was just pressed (using DirectInput's Buffered Input).
bool DirectInput_Manager::KeyPressedEx(unsigned char ucDIKey)		{ return (m_pKeyboard && m_pKeyboard->KeyPressedEx(ucDIKey)); }

//	Purpose	:	Gets the current (immediate) state of a Key.
bool DirectInput_Manager::KeyUp(unsigned char ucDIKey)				{ return (m_pKeyboard && m_pKeyboard->KeyUp(ucDIKey)); }

//	Purpose	:	To tell if a key was just released (without using DirectInput's Buffered Input).
bool DirectInput_Manager::KeyReleased(unsigned char ucDIKey)		{ return (m_pKeyboard && m_pKeyboard->KeyReleased(ucDIKey)); }

//	Purpose	:	To tell if a key was just released (using DirectInput's Buffered Input).
bool DirectInput_Manager::KeyReleasedEx(unsigned char ucDIKey)		{ return (m_pKeyboard && m_pKeyboard->KeyReleasedEx(ucDIKey)); }

//	Purpose	:	To get the ascii character value of the key the user typed.
//				So they can enter letters.
char DirectInput_Manager::CheckKeys(void)							{ return (m_pKeyboard) ? m_pKeyboard->CheckKeys() : 0; }

//	Purpose	:	To get the ascii character value of the key the user just typed.
//				So they can enter letters (using DirectInput's Buffered Input).
char DirectInput_Manager::CheckBufferedKeysEx(void)					{ return (m_pKeyboard) ? m_pKeyboard->CheckBufferedKeysEx() : 0; }

//	Purpose	:	To get the DIK code of the key the user is pressing.
//				For key binding.
unsigned char DirectInput_Manager::GetDIKCode(void)					{ return (m_pKeyboard) ? m_pKeyboard->GetDIKCode() : 0; }

//	Purpose	:	To get the DIK code of the key the user just pressed.
//				For key binding (using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
unsigned char DirectInput_Manager::GetBufferedDIKCodeEx(void)		{ return (m_pKeyboard) ? m_pKeyboard->GetBufferedDIKCodeEx() : 0; }

//	Purpose	:	Initialize the Mouse for DirectInput.
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::InitMouse(HWND hWnd, bool bIsExclusive)
{
	//	Make sure we aren't trying to do this a second time.
	if (m_pMouse)
	{
		DIERRBOX(hWnd, _T("Mouse has already been initialized"))
		return false;
	}

	m_pMouse = new DIMouse(m_lpDIObject, hWnd, bIsExclusive);
	
	if (m_pMouse == NULL)
		return false;

	return true;
}

//	Purpose	:	Gets the current (immediate) state of a mouse button.
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::MouseButtonDown(unsigned char ucButton)			{ return (m_pMouse && m_pMouse->ButtonDown(ucButton)); }

//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::MouseButtonPressed(unsigned char ucButton)		{ return (m_pMouse && m_pMouse->ButtonPressed(ucButton)); }

//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::MouseButtonPressedEx(unsigned char ucButton)	{ return (m_pMouse && m_pMouse->ButtonPressedEx(ucButton)); }

//	Purpose	:	Gets the current (immediate) state of a mouse button.
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::MouseButtonUp(unsigned char ucButton)			{ return (m_pMouse && m_pMouse->ButtonUp(ucButton)); }

//	Purpose	:	To tell if a mouse button was just released (without using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::MouseButtonReleased(unsigned char ucButton)		{ return (m_pMouse && m_pMouse->ButtonReleased(ucButton)); }

//	Purpose	:	To tell if a mouse button was just released (using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::MouseButtonReleasedEx(unsigned char ucButton)	{ return (m_pMouse && m_pMouse->ButtonReleasedEx(ucButton)); }

//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
int DirectInput_Manager::MouseCheckBufferedButtons(void)			{ return (m_pMouse) ? m_pMouse->CheckBufferedButtons() : -1; }

//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
int DirectInput_Manager::MouseCheckBufferedButtonsEx(void)			{ return (m_pMouse) ? m_pMouse->CheckBufferedButtonsEx() : -1; }

//	Purpose			:	To report the relative motion of the mouse 
//						in the X dimension.
///////////////////////////////////////////////////////////////////
long DirectInput_Manager::MouseMovementX(void)						{ return (m_pMouse) ? m_pMouse->MovementX() : 0; }

//	Purpose			:	To report the relative motion of the mouse 
//						in the Y dimension.
///////////////////////////////////////////////////////////////////
long DirectInput_Manager::MouseMovementY(void)						{ return (m_pMouse) ? m_pMouse->MovementY() : 0; }

//	Purpose			:	To report the relative motion of the mouse 
//						wheel.
///////////////////////////////////////////////////////////////////
long DirectInput_Manager::MouseWheelMovement(void)					{ return (m_pMouse) ? m_pMouse->WheelMovement() : 0; }

//	Purpose			:	To report the number of buttons on the device.
///////////////////////////////////////////////////////////////////
int DirectInput_Manager::MouseGetNumButtons(void)			{ return (m_pMouse) ? m_pMouse->GetNumButtons() : 0; }

//	Purpose			:	To help track the "psuedo" position of the mouse.
///////////////////////////////////////////////////////////////////
int DirectInput_Manager::MouseGetPosX(void)			{ return (m_pMouse) ? m_pMouse->GetPosX() : 0; }

//	Purpose			:	To help track the "psuedo" position of the mouse.
///////////////////////////////////////////////////////////////////
int DirectInput_Manager::MouseGetPosY(void)			{ return (m_pMouse) ? m_pMouse->GetPosY() : 0; }

//	Purpose			:	To set the "psuedo" position of the mouse.
///////////////////////////////////////////////////////////////////
void DirectInput_Manager::MouseSetPosX(int nPosX)			{ if (m_pMouse) m_pMouse->SetPosX( nPosX ); }

//	Purpose			:	To set the "psuedo" position of the mouse.
///////////////////////////////////////////////////////////////////
void DirectInput_Manager::MouseSetPosY(int nPosY)			{ if (m_pMouse) m_pMouse->SetPosY( nPosY ); }

///////////////////////////////////////////////////////////////////
//						JOYSTICKS								 //
///////////////////////////////////////////////////////////////////

//	Purpose	:	Initialize the joysticks for DirectInput.
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::InitJoysticks(HWND hWnd, bool bIsExclusive)
{
	//	Make sure we aren't trying to do this a second time.
	if (m_vpJoysticks.size() > 0)
	{
		DIERRBOX(hWnd, _T("Joysticks have already been initialized"))
		return false;
	}

	//	Remember the info in a struct to pass along
	tJoystickSetupInfo joySetupInfo = { hWnd, bIsExclusive };

	//	Enumerate all joysticks attached to the system.
	if(FAILED( m_lpDIObject->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, (LPVOID)&joySetupInfo, DIEDFL_ATTACHEDONLY) ))
		return false;

	//	If we don't have any joysticks, we couldn't initialize them
	if (m_vpJoysticks.size() == 0)
		return false;

	return true;
}

//	Purpose	:	Checks to see if there are any Joysticks presently attached to the computer.
///////////////////////////////////////////////////////////////////
BOOL CALLBACK DirectInput_Manager::EnumJoysticksCallback(const DIDEVICEINSTANCE* lpdidi, VOID* pVoid)
{
	DirectInput_Manager*	pDI = DirectInput_Manager::GetInstance();

	//	Retrieve the setup info
	tJoystickSetupInfo joySetupInfo = (*(tJoystickSetupInfo*)pVoid);

	//	Create the joystick
	DIJoystick* pJoystick = new DIJoystick(pDI->m_lpDIObject, joySetupInfo.hWnd, lpdidi, joySetupInfo.bIsExclusive);

	//	Failed to allocate the joystick
	if (pJoystick == NULL)
		return DIENUM_STOP; 

	//	Store the joystick.
	pDI->m_vpJoysticks.push_back(pJoystick);

	//	Continue looking for Joysticks.
	return DIENUM_CONTINUE;
}

//	Purpose	:	Gets the current (immediate) state of a joystick button.
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::JoystickButtonDown(unsigned char ucButton, int nJoyNum)			{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->ButtonDown(ucButton)); }

//	Purpose	:	To tell if a joystick button was just pressed (using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::JoystickButtonPressed(unsigned char ucButton, int nJoyNum)		{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->ButtonPressed(ucButton)); }

//	Purpose	:	To tell if a joystick button was just pressed (without using DirectInput's Buffered Input).
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::JoystickButtonPressedEx(unsigned char ucButton, int nJoyNum)	{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->ButtonPressedEx(ucButton)); }

//	Purpose	:	Gets the current (immediate) state of a joystick button.
///////////////////////////////////////////////////////////////////
bool DirectInput_Manager::JoystickButtonUp(unsigned char ucButton, int nJoyNum)			{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->ButtonUp(ucButton)); }

//	Purpose	:	To tell if a joystick button was just released (using DirectInput's Buffered Input).
bool DirectInput_Manager::JoystickButtonReleased(unsigned char ucButton, int nJoyNum)		{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->ButtonReleased(ucButton)); }

//	Return	:	true if the joystick button was released this frame.
//	Purpose	:	To tell if a joystick button was just released (without using DirectInput's Buffered Input).
bool DirectInput_Manager::JoystickButtonReleasedEx(unsigned char ucButton, int nJoyNum)	{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->ButtonReleasedEx(ucButton)); }

//	Purpose	:	To tell if a D-pad direction is down.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DirectInput_Manager::JoystickDPadDown(int nDir, int nJoyNum)			{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->DPadDown(nDir)); }

//	Purpose	:	To get the (buffered) direction the D-pad was pressed (without using DirectInput's Buffered Input).
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DirectInput_Manager::JoystickDPadPressed(int nDir, int nJoyNum)		{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->DPadPressed(nDir)); }

//	Purpose	:	To tell if a D-pad direction is up.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DirectInput_Manager::JoystickDPadUp(int nDir, int nJoyNum)			{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->DPadUp(nDir)); }

//	Purpose	:	To tell if a D-pad direction was just released (without using DirectInput's Buffered Input).
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DirectInput_Manager::JoystickDPadReleased(int nDir, int nJoyNum)		{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->DPadReleased(nDir)); }

///////////////////////////////////////////////////////////////////
//	Analog Sticks:
///////////////////////////////////////////////////////////////////

//	L-stick:
//	Purpose	:	To get the (immediate) direction the stick is being held.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DirectInput_Manager::JoystickGetLStickDirDown(int nDir, int nJoyNum)			{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->GetLStickDirDown(nDir)); }

//	Purpose	:	To get the (buffered) direction the stick was pressed (without using DirectInput's Buffered Input).
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DirectInput_Manager::JoystickGetLStickDirPressed(int nDir, int nJoyNum)		{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->GetLStickDirPressed(nDir)); }

//	Purpose	:	To get the position of the joystick in a digital range.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
int DirectInput_Manager::JoystickGetLStickXAmount(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetLStickXAmount() : 0; }

//	Purpose	:	To get the position of the joystick in a digital range.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
int DirectInput_Manager::JoystickGetLStickYAmount(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetLStickYAmount() : 0; }

//	Purpose	:	To get the position of the joystick in a normalized range.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
float DirectInput_Manager::JoystickGetLStickXNormalized(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetLStickXNormalized() : 0.0f; }

//	Purpose	:	To get the position of the joystick in a normalized range.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
float DirectInput_Manager::JoystickGetLStickYNormalized(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetLStickYNormalized() : 0.0f; }

//  R-stick:
//	Purpose	:	To get the (immediate) direction the stick is being held.
bool DirectInput_Manager::JoystickGetRStickDirDown(int nDir, int nJoyNum)			{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->GetRStickDirDown(nDir)); }

//	Purpose	:	To get the (buffered) direction the stick was pressed (without using DirectInput's Buffered Input).
bool DirectInput_Manager::JoystickGetRStickDirPressed(int nDir, int nJoyNum)		{ return ((nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) && m_vpJoysticks[nJoyNum]->GetRStickDirPressed(nDir)); }

//	Purpose	:	To get the position of the joystick in a digital range.
int DirectInput_Manager::JoystickGetRStickXAmount(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetRStickXAmount() : 0; }

//	Purpose	:	To get the position of the joystick in a digital range.
int DirectInput_Manager::JoystickGetRStickYAmount(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetRStickYAmount() : 0; }

//	Purpose	:	To get the position of the joystick in a normalized range.
float DirectInput_Manager::JoystickGetRStickXNormalized(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetRStickXNormalized() : 0.0f; }

//	Purpose	:	To get the position of the joystick in a normalized range.
float DirectInput_Manager::JoystickGetRStickYNormalized(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetRStickYNormalized() : 0.0f; }

//	Purpose	:	To get the position of the trigger in a digital range.
//	NOTE: If both triggers are pulled at the same time the reading won't 
//		  be accurate as their input is combined into one axis by DirectInput.
int DirectInput_Manager::JoystickGetLTriggerAmount(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetLTriggerAmount() : 0; }

//	Purpose	:	To get the position of the trigger in a digital range.
//	NOTE: If both triggers are pulled at the same time the reading won't 
//		  be accurate as their input is combined into one axis by DirectInput.
int DirectInput_Manager::JoystickGetRTriggerAmount(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetRTriggerAmount() : 0; }

//	Purpose	:	To get the position of the trigger in a normalized range.
//	NOTE: If both triggers are pulled at the same time the reading won't 
//		  be accurate as their input is combined into one axis by DirectInput.
float DirectInput_Manager::JoystickGetLTriggerNormalized(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetLTriggerNormalized() : 0.0f; }

//	Purpose	:	To get the position of the trigger in a normalized range.
//	NOTE: If both triggers are pulled at the same time the reading won't 
//		  be accurate as their input is combined into one axis by DirectInput.
float DirectInput_Manager::JoystickGetRTriggerNormalized(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetRTriggerNormalized() : 0.0f; }

//	Purpose	:	To tell which joystick button was just pressed (without using DirectInput's Buffered Input).
int DirectInput_Manager::JoystickCheckBufferedButtons(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->CheckBufferedButtons() : -1; }

//	Purpose	:	To tell which joystick button was just pressed (using DirectInput's Buffered Input).
int DirectInput_Manager::JoystickCheckBufferedButtonsEx(int nJoyNum)	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->CheckBufferedButtonsEx() : -1; }

//	Purpose			:	To report the number of buttons on the device.
int DirectInput_Manager::JoystickGetNumButtons(int nJoyNum) const	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetNumButtons() : 0; }


//	Purpose	:	Returns the true if the joystick is unplugged.
bool DirectInput_Manager::JoystickIsUnplugged(int nJoyNum) const	{ return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->IsUnplugged() : true; }

//	Purpose	:	Returns the name of the joystick (i.e. "Logitech RumblePad 2 USB")
const TCHAR* DirectInput_Manager::JoystickGetName(int nJoyNum)	const { return (nJoyNum >= 0 && nJoyNum < (int)m_vpJoysticks.size()) ? m_vpJoysticks[nJoyNum]->GetName() : _T("Doesn't exist"); }

//	Purpose	:	To swap the X/Y axes of certain controllers
//	NOTE:	Only works on non-Xbox360 controllers.
void DirectInput_Manager::JoystickSwapRStickAxes(bool bSwapAxes, int nJoyNum) { if (nJoyNum < 0 || nJoyNum >= (int)m_vpJoysticks.size()) return; m_vpJoysticks[nJoyNum]->SwapRStickAxes(bSwapAxes); }

//////////////////////////////////////////////////////////////////////////////////
//	DIKeyboard
//////////////////////////////////////////////////////////////////////////////////

DIKeyboard::DIKeyboard(LPDIRECTINPUT8 pDI, HWND hWnd, bool bIsExclusive)
{
	//	Create the Keyboard Device.
	if (FAILED( pDI->CreateDevice(GUID_SysKeyboard, &m_lpDevice, NULL) ))
	{
		DIERRBOX(hWnd, _T("Failed to create Keyboard device."))
	}

	//	Set the Data Format for the Keyboard.
	if (FAILED( m_lpDevice->SetDataFormat(&c_dfDIKeyboard) ))
	{
		DIERRBOX(hWnd, _T("Failed to set data format on Keyboard."))
	}

	//	Set the Cooperative level for the keyboard.
	DWORD dwFlags = DISCL_FOREGROUND;

	if (bIsExclusive)
		dwFlags |= DISCL_EXCLUSIVE;
	else
		dwFlags |= DISCL_NONEXCLUSIVE | DISCL_NOWINKEY;

	if (FAILED( m_lpDevice->SetCooperativeLevel(hWnd, dwFlags) ))
	{
		DIERRBOX(hWnd, _T("Failed to set cooperative level on Keyboard."))
	}

	//	Set up the device to use buffered input
	//	For Use With Buffered Input.
	DIPROPDWORD dipdw;

	//	Clear the structure to all zeroes.
	memset(&dipdw, 0, sizeof(dipdw));

	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj        = 0;
	dipdw.diph.dwHow        = DIPH_DEVICE;
	dipdw.dwData            = g_knBUFFER_SIZE;	//	Arbitrary buffer size

	//	Set the buffer size on the device.
	if (FAILED( m_lpDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) ))
		DIERRBOX(hWnd, _T("Could not Set the Properties for Buffered Input for Keyboard."))

	//	Acquire the Keyboard.
	if (FAILED( m_lpDevice->Acquire() ))
	{
		DIERRBOX(hWnd, _T("Failed to acquire Keyboard."))
	}	

	ClearKeys();

	//	Get the Keyboard Layout.
	m_keyLayout = GetKeyboardLayout(0);
}

//	Purpose	:	Reads the state of the device every frame.
bool DIKeyboard::ReadDevice(void)
{
	//	Make sure the keyboard device was made.
	if (!m_lpDevice)
		return false;

	//	Remember previously pressed keys
	memcpy(m_ucPrevKeysPressed, m_ucKeysPressed, sizeof(m_ucPrevKeysPressed));

	//	Attempt to read the keyboard...
	if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_ucKeysPressed), (LPVOID)m_ucKeysPressed) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Keyboard.

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_ucKeysPressed), (LPVOID)m_ucKeysPressed) ))
			return false;
	}

	//	Success.
	return true;
}

//	Purpose	:	Gets the DirectInput Buffered Data.
//	NOTE	:	For use with all Ex functions.
bool DIKeyboard::ReadBufferedDevice(void)
{
	//	Make sure the device was made.
	if (!m_lpDevice)
		return false;

	ClearBufferedData();

	//	Attempt to read the device...
	if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Device.

		ClearBufferedData();

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
			return false;
	}

	//	Success.
	return true;
}


//	Purpose	:	Gets the current (immediate) state of a Key.
bool DIKeyboard::KeyDown(unsigned char ucDIKey)
{
	//	if the high bit is on, it is pressed.
	return (m_ucKeysPressed[ucDIKey] & 0x80) ? true : false;
}

//	Purpose	:	To tell if a key was just pressed (without using DirectInput's Buffered Input).
bool DIKeyboard::KeyPressed(unsigned char ucDIKey)
{
	//	if the key is down and wasn't previously pressed.
	return KeyDown(ucDIKey) && !(m_ucPrevKeysPressed[ucDIKey] & 0x80);
}

//	Purpose	:	To tell if a key was just pressed (using DirectInput's Buffered Input).
bool DIKeyboard::KeyPressedEx(unsigned char ucDIKey)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the key we are looking for and the high bit is on, it is pressed.
		if ((m_didod[i].dwOfs == ucDIKey) && (m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}

//	Purpose	:	Gets the current (immediate) state of a Key.
bool DIKeyboard::KeyUp(unsigned char ucDIKey)
{
	//	if the high bit is off, it isn't pressed.
	return !KeyDown(ucDIKey);
}

//	Purpose	:	To tell if a key was just released (without using DirectInput's Buffered Input).
bool DIKeyboard::KeyReleased(unsigned char ucDIKey) // was key just released?
{
	//	if the key is up and was previously pressed.
	return KeyUp(ucDIKey) && (m_ucPrevKeysPressed[ucDIKey] & 0x80);
}

//	Purpose	:	To tell if a key was just released (using DirectInput's Buffered Input).
bool DIKeyboard::KeyReleasedEx(unsigned char ucDIKey) // uses DirectX Buffered Input
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the key we are looking for and the high bit is off, it was released.
		if ((m_didod[i].dwOfs == ucDIKey) && !(m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}

//	Purpose	:	To get the ascii character value of the key the user typed.
//				So they can enter letters.
char DIKeyboard::CheckKeys(void)
{	
	//	Get the Current Keyboard State.
	if ( !GetKeyboardState(m_ucAsciiVals) )
		return 0; // Could not GetKeyboardState.

	unsigned short usNum	= 0;
	unsigned int uiVKCode	= 0;

	//	Go through each keyboard key
	for (int i = 0; i < 256; i++)
	{
		// if the high bit is on, it is pressed
		if (KeyDown( (unsigned char)i ))
		{
			//	Map the Scan Code from DirectInput to a Virtual Key value...
			uiVKCode = MapVirtualKeyEx(i, 1, m_keyLayout);
			//	...and translate that Virtual Key into an Ascii Value.
			ToAsciiEx(uiVKCode, i, m_ucAsciiVals, &usNum, 0, m_keyLayout);
		}
	}

	//	Return the Ascii Value.
	return (char)usNum;
}

//	Purpose	:	To get the ascii character value of the key the user just typed.
//				So they can enter letters (using DirectInput's Buffered Input).
char DIKeyboard::CheckBufferedKeysEx(void)
{
	//	Get the Current Keyboard State.
	if (!(GetKeyboardState(m_ucAsciiVals)))
		return 0; // Could not GetKeyboardState.

	unsigned short usNum	= 0;
	unsigned int uiVKCode	= 0;

	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	Go through all keys on the keyboard
		for (unsigned int j = 0; j < 256; j++)
		{
			//	If the offset matches the key we are looking for and the high bit is on, it is pressed.
			if ((m_didod[i].dwOfs == j) && (m_didod[i].dwData & 0x80))
			{
				//	Map the Scan Code from DirectInput to a Virtual Key value...
				uiVKCode = MapVirtualKeyEx(m_didod[i].dwOfs, 1, m_keyLayout);
				//	...and translate that Virtual Key into an Ascii Value.
				ToAsciiEx(uiVKCode, m_didod[i].dwOfs, m_ucAsciiVals, &usNum, 0, m_keyLayout);
			}
		}
	}

	//	Return the Ascii Value.
	return (char)usNum;	
}

//	Purpose	:	To get the DIK code of the key the user is pressing.
//				For key binding.
unsigned char DIKeyboard::GetDIKCode(void)
{	
	unsigned char ucNum = 0;

	//	Go through each keyboard key
	for (int i = 0; i < 256; i++)
	{
		// find the first one that is pressed
		if (KeyDown( (unsigned char)i ))
		{
			ucNum = (unsigned char)i;
			break;
		}
	}

	//	Return the DIK Code.
	return ucNum;
}

//	Purpose	:	To get the DIK code of the key the user just pressed.
//				For key binding (using DirectInput's Buffered Input).
unsigned char DIKeyboard::GetBufferedDIKCodeEx(void)
{
	unsigned char ucNum = 0;

	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	Go through all keys on the keyboard
		for (unsigned int j = 0; j < 256; j++)
		{
			//	If the offset matches the key we are looking for and the high bit is on, it is pressed.
			if ((m_didod[i].dwOfs == j) && (m_didod[i].dwData & 0x80))
			{
				ucNum = (unsigned char)j;
				break;
			}
		}
	}

	//	Return the DIK Code.
	return ucNum;	
}

///////////////////////////////////////////////////////////////////////////////////////////
//	CSGD_DIMouse
///////////////////////////////////////////////////////////////////////////////////////////

//	Purpose	:	Setup the mouse for use with DirectInput.
DIMouse::DIMouse(LPDIRECTINPUT8 pDI, HWND hWnd, bool bIsExclusive)
{
	//	Create the Mouse Device.
	if (FAILED( pDI->CreateDevice(GUID_SysMouse, &m_lpDevice, NULL) ))
	{
		DIERRBOX(hWnd, _T("Failed to create Mouse device."))
	}

	//	Set the Data Format for the Mouse.
	if (FAILED( m_lpDevice->SetDataFormat(&c_dfDIMouse2) ))
	{
		DIERRBOX(hWnd, _T("Failed to set data format on Mouse."))
	}

	//	Set the Cooperative level for the mouse.
	DWORD dwFlags = DISCL_FOREGROUND;

	if (bIsExclusive)
		dwFlags |= DISCL_EXCLUSIVE;
	else
		dwFlags |= DISCL_NONEXCLUSIVE;

	if (FAILED( m_lpDevice->SetCooperativeLevel(hWnd, dwFlags) ))
	{
		DIERRBOX(hWnd, _T("Failed to set cooperative level on Mouse."))
	}

	//	Set up the device to use buffered input
	//	For Use With Buffered Input.
	DIPROPDWORD dipdw;

	//	Clear the structure to all zeroes.
	memset(&dipdw, 0, sizeof(dipdw));

	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj        = 0;
	dipdw.diph.dwHow        = DIPH_DEVICE;
	dipdw.dwData            = g_knBUFFER_SIZE;	//	Arbitrary buffer size

	//	Set the buffer size on the device.
	if (FAILED( m_lpDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) ))
		DIERRBOX(hWnd, _T("Could not Set the Properties for Buffered Input for Mouse."))

	//	Acquire the Mouse.
	if (FAILED( m_lpDevice->Acquire() ))
	{
		DIERRBOX(hWnd, _T("Failed to acquire Mouse."))
	}	

	// DIDC_ATTACHED 
	// DIDC_FORCEFEEDBACK
	// DIDC_POLLEDDATAFORMAT VS DIDC_POLLEDDEVICE 
	// dwAxes 
	// dwButtons 
	// dwPOVs 
	DIDEVCAPS  didCaps;

	// clear out struct
	memset(&didCaps, 0, sizeof(didCaps));
	didCaps.dwSize = sizeof(didCaps); 

	//if (SUCCEEDED( m_lpDevice->GetCapabilities(&didCaps) ))
	m_lpDevice->GetCapabilities(&didCaps);
	{
		if (didCaps.dwFlags & DIDC_POLLEDDATAFORMAT)
			int y = 4;
		if (didCaps.dwFlags & DIDC_POLLEDDEVICE)
			int y = 5;
	}

	// will be zero if it failed because the struct was cleared out
	m_nNumButtons = didCaps.dwButtons;

	//	clear out current state
	memset(&m_diMouseState, 0, sizeof(m_diMouseState));
	//	clear prev state
	memset(&m_diPrevMouseState, 0, sizeof(m_diPrevMouseState));

	//	Set psuedo position of mouse
	SetPosX( 0 );
	SetPosY( 0 );
}

//	Purpose	:	Reads the state of the device every frame.
bool DIMouse::ReadDevice(void)
{
	//	Make sure the mouse device was made.
	if (!m_lpDevice)
		return false;

	//	Remember previous state
	memcpy(&m_diPrevMouseState, &m_diMouseState, sizeof(m_diPrevMouseState));

	//	Attempt to read the mouse...
	if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_diMouseState), (LPVOID)&m_diMouseState) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Mouse.

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_diMouseState), (LPVOID)&m_diMouseState) ))
			return false;
	}

	// Update "psuedo" position of mouse
	SetPosX( GetPosX() + MovementX() );
	SetPosY( GetPosY() + MovementY() );

	//	Success.
	return true;
}

//	Purpose	:	Gets the DirectInput Buffered Data.
//	NOTE	:	For all Ex functions.
bool DIMouse::ReadBufferedDevice(void)
{
	//	Make sure the device was made.
	if (!m_lpDevice)
		return false;

	ClearBufferedData();

	//	Attempt to read the device...
	if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Device.

		ClearBufferedData();

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
			return false;
	}

	//	Success.
	return true;
}

//	Purpose	:	Gets the current (immediate) state of a mouse button.
bool DIMouse::ButtonDown(unsigned char ucButton)
{
	//	if the high bit is on, it is pressed.
	return (m_diMouseState.rgbButtons[ucButton] & 0x80) ? true : false;
}

//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
bool DIMouse::ButtonPressed(unsigned char ucButton)
{
	//	if the button is down and wasn't previously pressed.
	return ButtonDown(ucButton) && !(m_diPrevMouseState.rgbButtons[ucButton] & 0x80);
}

//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
bool DIMouse::ButtonPressedEx(unsigned char ucButton)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the button we are looking for and the high bit is on, it is pressed.
		if ((m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + ucButton)) && (m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}

//	Purpose	:	Gets the current (immediate) state of a mouse button.
bool DIMouse::ButtonUp(unsigned char ucButton)
{
	//	if the high bit is off, it isn't pressed.
	return !ButtonDown(ucButton);
}

//	Purpose	:	To tell if a mouse button was just released (without using DirectInput's Buffered Input).
bool DIMouse::ButtonReleased(unsigned char ucButton)
{
	//	if the button is up and was previously pressed.
	return ButtonUp(ucButton) && (m_diPrevMouseState.rgbButtons[ucButton] & 0x80);
}

//	Purpose	:	To tell if a mouse button was just released (using DirectInput's Buffered Input).
bool DIMouse::ButtonReleasedEx(unsigned char ucButton)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the button we are looking for and the high bit is off, it was released.
		if ((m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + ucButton)) && !(m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}

//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
int DIMouse::CheckBufferedButtons(void)
{
	int nButton = -1;

	//	Go through all mouse buttons.
	for (int j = 0; j < GetNumButtons(); j++)
	{
		//	Find the first button that was pressed
		if (ButtonPressed(j))
		{
			//	return the first one that was found to be pressed.
			nButton = j;
			break;
		}
	}

	//	return the button.
	return nButton;
}

//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
int DIMouse::CheckBufferedButtonsEx(void)
{
	int nButton = -1;

	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	Go through all mouse buttons.
		for (int j = 0; j < GetNumButtons(); j++)
		{
			//	If the offset matches the button we are looking for and the high bit is on, it is pressed.
			if ((m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + j)) && (m_didod[i].dwData & 0x80))
			{
				//	return the first one that was found to be pressed.
				nButton = j;
				break;
			}
		}
	}

	//	return the button.
	return nButton;
}

//	Purpose			:	To report the relative motion of the mouse 
//						in the X dimension.
long DIMouse::MovementX(void)
{
	return m_diMouseState.lX;
}

//	Purpose			:	To report the relative motion of the mouse 
//						in the Y dimension.
long DIMouse::MovementY(void)
{
	return m_diMouseState.lY;
}

//	Purpose			:	To report the relative motion of the mouse 
//						wheel.
long DIMouse::WheelMovement(void)
{
	return m_diMouseState.lZ;
}

///////////////////////////////////////////////////////////////////////////////////////////
//	DIJoystick
///////////////////////////////////////////////////////////////////////////////////////////

//	Constants:
const int	JOYSTICK_AXIS_RANGE = 1024;
const float PERCENTAGE_RANGE	= 0.7f;
const int	JOYSTICK_THRESHOLD	= (int)(JOYSTICK_AXIS_RANGE * PERCENTAGE_RANGE);

const float ONE_OVER_RANGE = 1.0f / (float)JOYSTICK_AXIS_RANGE;

//	Purpose	:	Setup the joystick for use with DirectInput.
DIJoystick::DIJoystick(LPDIRECTINPUT8 pDI, HWND hWnd, const DIDEVICEINSTANCE* lpdidi, bool bIsExclusive)
{
	//	For error reporting
	TCHAR szErrorBuffer[256];

	//	Get the Joystick Name and store it.
	_tcscpy_s(m_szJoyName, _countof(m_szJoyName), lpdidi->tszProductName);

	// Remember if it is an Xbox 360 pad
	m_bIsXbox360Pad = (_tcscmp(m_szJoyName, _T("Xbox 360 Wireless Receiver for Windows")) == 0 || _tcscmp(m_szJoyName, _T("Controller (XBOX 360 For Windows)")) == 0) ? true : false;

	//	Create the Joystick Device.
	if (FAILED( pDI->CreateDevice(lpdidi->guidInstance, &m_lpDevice, NULL) ))
	{
		_stprintf_s(szErrorBuffer, _countof(szErrorBuffer), _T("Failed to create Joystick device: %s"), m_szJoyName);
		DIERRBOX(hWnd, szErrorBuffer)
	}

	//	Set the Data Format for the Joystick.
	if (FAILED( m_lpDevice->SetDataFormat(&c_dfDIJoystick2) ))
	{
		_stprintf_s(szErrorBuffer, _countof(szErrorBuffer), _T("Failed to set data format on Joystick: %s"), m_szJoyName);
		DIERRBOX(hWnd, szErrorBuffer)
	}

	//	Get Capablities:
	// DIDC_ATTACHED 
	// DIDC_FORCEFEEDBACK
	// DIDC_POLLEDDATAFORMAT VS DIDC_POLLEDDEVICE 
	// dwAxes 
	// dwButtons 
	// dwPOVs 
	DIDEVCAPS  didCaps;

	// clear out struct
	memset(&didCaps, 0, sizeof(didCaps));
	didCaps.dwSize = sizeof(didCaps); 

	//if (SUCCEEDED( m_lpDevice->GetCapabilities(&didCaps) ))
	m_lpDevice->GetCapabilities(&didCaps);
	{
		if (didCaps.dwFlags & DIDC_POLLEDDATAFORMAT)
			int y = 4;
		if (didCaps.dwFlags & DIDC_POLLEDDEVICE)
			int y = 5;

		if (didCaps.dwFlags & DIDC_FORCEFEEDBACK)
			bIsExclusive = true; // forces true so that the device can use ForceFeedback (has to be exclusive to use FF).
	}

	DWORD axes = didCaps.dwAxes;
	DWORD povs = didCaps.dwPOVs;

	// will be zero if it failed because the struct was cleared out
	m_nNumButtons = didCaps.dwButtons;

	//	Set the Cooperative level for the Joystick.
	DWORD dwFlags = DISCL_FOREGROUND;

	if (bIsExclusive)
		dwFlags |= DISCL_EXCLUSIVE;
	else
		dwFlags |= DISCL_NONEXCLUSIVE;

	if (FAILED( m_lpDevice->SetCooperativeLevel(hWnd, dwFlags) ))
	{
		_stprintf_s(szErrorBuffer, _countof(szErrorBuffer), _T("Failed to set cooperative level on Joystick: %s"), m_szJoyName);
		DIERRBOX(hWnd, szErrorBuffer)
	}

	//	Set the Properties for the Joystick Axes:

	//	Set the ranges for the axes:
	DIPROPRANGE dipr;
	dipr.diph.dwSize		= sizeof(DIPROPRANGE);
	dipr.diph.dwHeaderSize	= sizeof(DIPROPHEADER);
	dipr.diph.dwHow			= DIPH_BYOFFSET;
	dipr.lMin				= -JOYSTICK_AXIS_RANGE;	//	Minimum range.
	dipr.lMax				= +JOYSTICK_AXIS_RANGE;	//	Maximum range.

	dipr.diph.dwObj			= DIJOFS_X;				//	Change the X-Axis.
	m_lpDevice->SetProperty(DIPROP_RANGE, &dipr.diph);

	//	Change the Y-Axis.
	dipr.diph.dwObj			= DIJOFS_Y;
	m_lpDevice->SetProperty(DIPROP_RANGE, &dipr.diph);

	//	Is it not an Xbox360 controller?
	if (!m_bIsXbox360Pad)
	{
		//	Change the Z-Axis //(left/right on R-stick).
		dipr.diph.dwObj			= DIJOFS_Z;
		m_lpDevice->SetProperty(DIPROP_RANGE, &dipr.diph);

		//	Change the RotationZ-Axis //(up/down on R-stick).
		dipr.diph.dwObj			= DIJOFS_RZ;
		m_lpDevice->SetProperty(DIPROP_RANGE, &dipr.diph);
	}
	else // it is an Xbox360 controller
	{
		//	Change the Z-Axis (for L + R triggers).
		dipr.diph.dwObj			= DIJOFS_Z;
		m_lpDevice->SetProperty(DIPROP_RANGE, &dipr.diph);

		//	Change the RotationX-Axis (left/right on R-stick).
		dipr.diph.dwObj			= DIJOFS_RX;
		m_lpDevice->SetProperty(DIPROP_RANGE, &dipr.diph);

		//	Change the RotationY-Axis (up/down on R-stick).
		dipr.diph.dwObj			= DIJOFS_RY;
		m_lpDevice->SetProperty(DIPROP_RANGE, &dipr.diph);
	}

	//	Setup a Dead Zone for the axes.
	DIPROPDWORD deadZone;
	deadZone.diph.dwSize	   = sizeof (deadZone);
	deadZone.diph.dwHeaderSize = sizeof (deadZone.diph);
	deadZone.diph.dwObj		   = DIJOFS_X;
	deadZone.diph.dwHow		   = DIPH_BYOFFSET;
	deadZone.dwData			   = 1000;

	//	Setup the X-Axis Dead Zone.
	m_lpDevice->SetProperty(DIPROP_DEADZONE, &deadZone.diph);

	//	Setup the Y-Axis Dead Zone.
	deadZone.diph.dwObj		   = DIJOFS_Y;
	m_lpDevice->SetProperty(DIPROP_DEADZONE, &deadZone.diph);

	if (!m_bIsXbox360Pad)
	{
		//	Setup the Z-Axis Dead Zone.
		deadZone.diph.dwObj		   = DIJOFS_Z;
		m_lpDevice->SetProperty(DIPROP_DEADZONE, &deadZone.diph);

		//	Setup the ZR-Axis Dead Zone.
		deadZone.diph.dwObj		   = DIJOFS_RZ;
		m_lpDevice->SetProperty(DIPROP_DEADZONE, &deadZone.diph);
	}
	else
	{
		//	Setup the Z-Axis Dead Zone.
		//deadZone.diph.dwObj		   = DIJOFS_Z;
		//m_lpDevice->SetProperty(DIPROP_DEADZONE, &deadZone.diph);

		//	Setup the RotationX-Axis Dead Zone.
		deadZone.diph.dwObj		   = DIJOFS_RX;
		m_lpDevice->SetProperty(DIPROP_DEADZONE, &deadZone.diph);
		
		//	Setup the RotationY-Axis Dead Zone.
		deadZone.diph.dwObj		   = DIJOFS_RY;
		m_lpDevice->SetProperty(DIPROP_DEADZONE, &deadZone.diph);
	}

	//	Set up the device to use buffered input
	//	For Use With Buffered Input.
	DIPROPDWORD dipdw;

	//	Clear the structure to all zeroes.
	memset(&dipdw, 0, sizeof(dipdw));

	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj        = 0;
	dipdw.diph.dwHow        = DIPH_DEVICE;
	dipdw.dwData            = g_knBUFFER_SIZE;	//	Arbitrary buffer size

	//	Set the buffer size on the device.
	if (FAILED( m_lpDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) ))
	{
		_stprintf_s(szErrorBuffer, _countof(szErrorBuffer), _T("Could not Set the Properties for Buffered Input for Joystick: %s"), m_szJoyName);
		DIERRBOX(hWnd, szErrorBuffer)
	}

	//	Acquire the Joystick.
	if (FAILED( m_lpDevice->Acquire() ))
	{
		_stprintf_s(szErrorBuffer, _countof(szErrorBuffer), _T("Failed to acquire Joystick: %s"), m_szJoyName);
		DIERRBOX(hWnd, szErrorBuffer)
	}

	//	clear out struct
	memset(&m_diJoyState, 0, sizeof(m_diJoyState));
	memset(&m_diPrevJoyState, 0, sizeof(m_diPrevJoyState));

	m_bIsUnplugged = false;

	SwapRStickAxes(false); // Z axis is considered R-stick's X-axis
}

//	Return	:	true if it can read the device state, false if it can't.
//	Purpose	:	Reads the state of the device every frame.
bool DIJoystick::ReadDevice(void)
{
	//	Make sure the joystick device was made.
	if (!m_lpDevice)
		return false;

	//	Remember the previous state of the joystick
	memcpy(&m_diPrevJoyState, &m_diJoyState, sizeof(m_diPrevJoyState));

	//	Clear out the current state's data
	memset(&m_diJoyState, 0, sizeof(m_diJoyState));

	//	Poll the joystick to update its state
	if (FAILED( m_lpDevice->Poll() ))
	{
		//	Try to Acquire the Joystick.
		HRESULT hr = m_lpDevice->Acquire();

		//	Make sure the joystick is plugged in.
		if (!m_bIsUnplugged)
		{
			//	Check if the joystick was unplugged
			if (hr == DIERR_UNPLUGGED)
				m_bIsUnplugged = true;
		}

		//	Try to re-acquire the joystick if it is unplugged.
		if (m_bIsUnplugged)
		{
			if (SUCCEEDED( m_lpDevice->Acquire() ))
				m_bIsUnplugged = false;
		}

		//	If no input from joystick re-acquire.
		if (hr == DIERR_INPUTLOST)
			hr = m_lpDevice->Acquire();

		//	Success.
		//return true;
	}
	
	//	Attempt to read the joystick state...
	if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_diJoyState), (LPVOID)&m_diJoyState) ))
		return false;

	//	Success.
	return true;
}

//	Purpose	:	Gets the Buffered Device Data every frame.
//	NOTE	:	Not for use with Ex functions (use ReadDevice() for that).
bool DIJoystick::ReadBufferedDevice(void)
{
	//	Make sure the device was made.
	if (!m_lpDevice)
		return false;

	ClearBufferedData();

	//	Attempt to read the device...
	if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Device.

		ClearBufferedData();

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
			return false;
	}

	//	Success.
	return true;
}

//	Purpose	:	Toggles whether the Z or RotationZ axis is considered the Y Axis.
//	NOTE	:	Defaults to RotationZ is Y Axis.
void DIJoystick::SwitchRStickAxes(void)
{
	m_bIsZAxisY = !m_bIsZAxisY;
}

//	Purpose	:	Gets the current (immediate) state of a joystick button.
bool DIJoystick::ButtonDown(unsigned char ucButton)
{
	//	if the high bit is on, it is pressed.
	return (m_diJoyState.rgbButtons[ucButton] & 0x80) ? true : false;
}

//	Purpose	:	To tell if a joystick button was just pressed (without using DirectInput's Buffered Input).
bool DIJoystick::ButtonPressed(unsigned char ucButton)
{
	//	if the button is down and wasn't previously pressed.
	return ButtonDown(ucButton) && !(m_diPrevJoyState.rgbButtons[ucButton] & 0x80);
}

//	Purpose	:	To tell if a joystick button was just pressed (using DirectInput's Buffered Input).
bool DIJoystick::ButtonPressedEx(unsigned char ucButton)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the button we are looking for and the high bit is on, it is pressed.
		if ((m_didod[i].dwOfs == (DWORD)DIJOFS_BUTTON(ucButton)) && (m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}

//	Purpose	:	Gets the current (immediate) state of a joystick button.
bool DIJoystick::ButtonUp(unsigned char ucButton)
{
	//	if the high bit is off, it isn't pressed.
	return !ButtonDown(ucButton);
}

//	Purpose	:	To tell if a joystick button was just released (without using DirectInput's Buffered Input).
bool DIJoystick::ButtonReleased(unsigned char ucButton)
{
	//	if the button is up and was previously pressed.
	return ButtonUp(ucButton) && (m_diPrevJoyState.rgbButtons[ucButton] & 0x80);
}

//	Purpose	:	To tell if a joystick button was just released (using DirectInput's Buffered Input).
bool DIJoystick::ButtonReleasedEx(unsigned char ucButton)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the button we are looking for and the high bit is off, it was released.
		if ((m_didod[i].dwOfs == (DWORD)(DWORD)DIJOFS_BUTTON(ucButton)) && !(m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}


//	Purpose	:	Translates a checked for direction from a numerical mess.
bool DIJoystick::TranslatePOV(int nDir, DWORD dwPOVDir)
{
	// means neutral
	bool bIsPOVCentered = (LOWORD(dwPOVDir) == 0xFFFF);
	
	if (bIsPOVCentered)
		return false;

	int nPOV = (int)LOWORD(dwPOVDir);

	switch(nDir)
	{
		case DIR_UP: // could be up/left, up, or up/right.
		{
			return (nPOV > POV_LEFT || nPOV < POV_RIGHT);
		}
		break;

		case DIR_DOWN: // could be dwn/left, dwn, or dwn/right.
		{
			return (nPOV > POV_RIGHT && nPOV < POV_LEFT);
		}
		break;

		case DIR_LEFT: // could be up/left, left, or dwn/left.
		{
			return (/*dwPOVDir > POV_UP && */nPOV > POV_DOWN);
		}
		break;

		case DIR_RIGHT: // could be up/right, right, or dwn/right.
		{
			return (nPOV > POV_UP && nPOV < POV_DOWN);
		}
		break;
	};

	return false;
}

//	Purpose	:	To get the position of the joystick in a digital range.
LONG DIJoystick::TranslateRStickX(DIJOYSTATE2& diJoyState)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return 0;

	//	Check for the Direction.
	if (!m_bIsXbox360Pad)
	{
		return (m_bIsZAxisY) ? diJoyState.lRz : diJoyState.lZ;
	}
	else	//	is Xbox 360 pad
	{
		return diJoyState.lRx;
	}
}

//	Purpose	:	To get the position of the joystick in a digital range.
LONG DIJoystick::TranslateRStickY(DIJOYSTATE2& diJoyState)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return 0;

	//	Check for the Direction.
	if (!m_bIsXbox360Pad)
	{
		return (m_bIsZAxisY) ? diJoyState.lZ : diJoyState.lRz; 
	}
	else	//	is Xbox 360 pad
	{
		return diJoyState.lRy;
	}
}

///////////////////////////////////////////////////////////////////
//	D-pad:
///////////////////////////////////////////////////////////////////

//	Purpose	:	To tell if a D-pad direction is down.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DIJoystick::DPadDown(int nDir)
{
	DWORD dwDir = m_diJoyState.rgdwPOV[0];

	return TranslatePOV(nDir, m_diJoyState.rgdwPOV[0]);
}

//	Purpose	:	To get the (buffered) direction the D-pad was pressed (without using DirectInput's Buffered Input).
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DIJoystick::DPadPressed(int nDir)
{
	//	If the d-pad is down and wasn't previously.
	return DPadDown(nDir) && !TranslatePOV(nDir, m_diPrevJoyState.rgdwPOV[0]);
}

//	Purpose	:	To tell if a D-pad direction is up.
//
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
///////////////////////////////////////////////////////////////////
bool DIJoystick::DPadUp(int nDir)
{
	return !DPadDown(nDir);
}

//	Purpose	:	To tell if a D-pad direction was just released (without using DirectInput's Buffered Input).
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DIJoystick::DPadReleased(int nDir)
{
	//	if the direction isn't down and was previously pressed.
	return !DPadDown(nDir) && TranslatePOV(nDir, m_diPrevJoyState.rgdwPOV[0]);
}

///////////////////////////////////////////////////////////////////
//	Analog Sticks:
///////////////////////////////////////////////////////////////////

//	L-stick:
//	Purpose	:	To get the (immediate) direction the stick is being held.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DIJoystick::GetLStickDirDown(int nDir)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return false;

	//	Check for the Direction.
	switch(nDir)
	{
		case DIR_LEFT:
		{
			if (m_diJoyState.lX < 0) 
				return true;
		}		
		break;

		case DIR_RIGHT:
		{
			if (m_diJoyState.lX > 0) 
				return true;
		}	
		break;

		case DIR_UP:
		{
			if (m_diJoyState.lY < 0) 
				return true;
		}
		break;

		case DIR_DOWN:
		{
			if (m_diJoyState.lY > 0) 
				return true;
		}	
		break;
	};

	//	The direction wasn't pressed.
	return false;
}

//	Purpose	:	To get the (buffered) direction the stick was pressed (without using DirectInput's Buffered Input).
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
bool DIJoystick::GetLStickDirPressed(int nDir)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return false;

	//	Check for the Direction.
	switch(nDir)
	{
		case DIR_LEFT:
		{
			if (m_diJoyState.lX < -JOYSTICK_THRESHOLD && !(m_diPrevJoyState.lX < -JOYSTICK_THRESHOLD)) 
				return true;
		}		
		break;

		case DIR_RIGHT:
		{
			if (m_diJoyState.lX > JOYSTICK_THRESHOLD && !(m_diPrevJoyState.lX > JOYSTICK_THRESHOLD)) 
				return true;
		}	
		break;

		case DIR_UP:
		{
			if (m_diJoyState.lY < -JOYSTICK_THRESHOLD && !(m_diPrevJoyState.lY < -JOYSTICK_THRESHOLD)) 
				return true;
		}
		break;

		case DIR_DOWN:
		{
			if (m_diJoyState.lY > JOYSTICK_THRESHOLD && !(m_diPrevJoyState.lY > JOYSTICK_THRESHOLD)) 
				return true;
		}	
		break;
	};

	//	The direction wasn't pressed.
	return false;
}

//	Purpose	:	To get the position of the joystick in a digital range.
//
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
int DIJoystick::GetLStickXAmount(void)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return 0;

	return m_diJoyState.lX;
}

//	Purpose	:	To get the position of the joystick in a digital range.
//
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
int DIJoystick::GetLStickYAmount(void)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return 0;

	return m_diJoyState.lY;
}

//	Purpose	:	To get the position of the joystick in a normalized range.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
float DIJoystick::GetLStickXNormalized()
{
	return (float)GetLStickXAmount() * ONE_OVER_RANGE;			// same as dividing by JOYSTICK_AXIS_RANGE (but twice as fast!)
}

//	Purpose	:	To get the position of the joystick in a normalized range.
//	NOTE:	L-stick and D-pad can usually be swapped by pressing a "Mode" button on the controller.
float DIJoystick::GetLStickYNormalized()
{
	return (float)GetLStickYAmount() * ONE_OVER_RANGE;			// same as dividing by JOYSTICK_AXIS_RANGE (but twice as fast!)
}

//  R-stick:
//	Purpose	:	To get the (immediate) direction the stick is being held.
bool DIJoystick::GetRStickDirDown(int nDir)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return false;

	switch(nDir)
	{
		case DIR_LEFT:
		{
			if ( TranslateRStickX(m_diJoyState) < 0 ) 
				return true;
		}		
		break;

		case DIR_RIGHT:
		{
			if ( TranslateRStickX(m_diJoyState) > 0 ) 
				return true;
		}	
		break;

		case DIR_UP:
		{
			if ( TranslateRStickY(m_diJoyState) < 0 ) 
				return true;
		}
		break;

		case DIR_DOWN:
		{
			if ( TranslateRStickY(m_diJoyState) > 0 ) 
				return true;
		}	
		break;
	};

	//	The direction wasn't pressed.
	return false;
}

//	Purpose	:	To get the (buffered) direction the stick was pressed (without using DirectInput's Buffered Input).
bool DIJoystick::GetRStickDirPressed(int nDir)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return false;

	//	Check for the Direction.
	switch(nDir)
	{
		case DIR_LEFT:
		{
			if ( TranslateRStickX(m_diJoyState) < -JOYSTICK_THRESHOLD && !(TranslateRStickX(m_diPrevJoyState) < -JOYSTICK_THRESHOLD) ) 
				return true;
		}		
		break;

		case DIR_RIGHT:
		{
			if ( TranslateRStickX(m_diJoyState) > JOYSTICK_THRESHOLD && !(TranslateRStickX(m_diPrevJoyState) > JOYSTICK_THRESHOLD) ) 
				return true;
		}	
		break;

		case DIR_UP:
		{
			if ( TranslateRStickY(m_diJoyState) < -JOYSTICK_THRESHOLD && !(TranslateRStickY(m_diPrevJoyState) < -JOYSTICK_THRESHOLD) ) 
				return true;
		}
		break;

		case DIR_DOWN:
		{
			if ( TranslateRStickY(m_diJoyState) > JOYSTICK_THRESHOLD && !(TranslateRStickY(m_diPrevJoyState) > JOYSTICK_THRESHOLD) ) 
				return true;
		}	
		break;
	};

	//	The direction wasn't pressed.
	return false;
}

//	Purpose	:	To get the position of the joystick in a digital range.
int DIJoystick::GetRStickXAmount(void)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return 0;

	return TranslateRStickX(m_diJoyState);
}

//	Purpose	:	To get the position of the joystick in a digital range.
int DIJoystick::GetRStickYAmount(void)
{
	//	Make sure the device is valid.
	if (!m_lpDevice)
		return 0;

	return TranslateRStickY(m_diJoyState);
}

//	Purpose	:	To get the position of the joystick in a normalized range.
float DIJoystick::GetRStickXNormalized()
{
	return (float)GetRStickXAmount() * ONE_OVER_RANGE;			// same as dividing by JOYSTICK_AXIS_RANGE (but twice as fast!)
}

//	Purpose	:	To get the position of the joystick in a normalized range.
float DIJoystick::GetRStickYNormalized()
{
	return (float)GetRStickYAmount() * ONE_OVER_RANGE;			// same as dividing by JOYSTICK_AXIS_RANGE (but twice as fast!)
}

//	Purpose	:	To get the position of the trigger in a digital range.
//
//	NOTE: If both triggers are pulled at the same time the reading won't 
//		  be accurate as their input is combined into one axis by DirectInput.
int DIJoystick::GetLTriggerAmount(void)
{
	if (!m_bIsXbox360Pad) return 0;

	return m_diJoyState.lZ;
}

//	Purpose	:	To get the position of the trigger in a digital range.
//
//	NOTE: If both triggers are pulled at the same time the reading won't 
//		  be accurate as their input is combined into one axis by DirectInput.
int DIJoystick::GetRTriggerAmount(void)
{
	if (!m_bIsXbox360Pad) return 0;

	return -m_diJoyState.lZ; // - to take into account that it is actually 0 to -JOYSTICK_AXIS_RANGE
}


//	Purpose	:	To get the position of the trigger in a normalized range.
//
//	NOTE: If both triggers are pulled at the same time the reading won't 
//		  be accurate as their input is combined into one axis by DirectInput.
float DIJoystick::GetLTriggerNormalized(void)
{
	return GetRTriggerAmount() * ONE_OVER_RANGE;	// same as dividing by JOYSTICK_AXIS_RANGE (but twice as fast!)
}

//	Purpose	:	To get the position of the trigger in a normalized range.
//
//	NOTE: If both triggers are pulled at the same time the reading won't 
//		  be accurate as their input is combined into one axis by DirectInput.
float DIJoystick::GetRTriggerNormalized(void)
{
	return GetRTriggerAmount() * ONE_OVER_RANGE;	// same as dividing by JOYSTICK_AXIS_RANGE (but twice as fast!)
}

//	Purpose	:	To tell which joystick button was just pressed (without using DirectInput's Buffered Input).
int	DIJoystick::CheckBufferedButtons(void)
{
	int nButton = -1;

	//	Go through all joystick buttons.
	for (int j = 0; j < GetNumButtons(); j++)
	{
		//	Check if the button was just pressed
		if (ButtonPressed((unsigned char)j))
		{
			//	return the first one that was found to be pressed.
			nButton = j;
			break;
		}
	}

	//	return the button.
	return nButton;
}

//	Purpose	:	To tell which joystick button was just pressed (using DirectInput's Buffered Input).
int DIJoystick::CheckBufferedButtonsEx(void)
{
	int nButton = -1;

	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	Go through all joystick buttons.
		for (int j = 0; j < GetNumButtons(); j++)
		{
			//	If the offset matches the button we are looking for and the high bit is on, it is pressed.
			if ((m_didod[i].dwOfs == (DWORD)(DWORD)DIJOFS_BUTTON(j)) && (m_didod[i].dwData & 0x80))
			{
				//	return the first one that was found to be pressed.
				nButton = j;
				break;
			}
		}
	}

	//	return the button.
	return nButton;
}